/**
 * View
 *
 * new View({
 *  container : "#main",
 *  model : model
 * });
 * ------------------------------------
 *
 * API:
 * ------------------------------------
 * draw()
 * setModel(model)
 *
 */
(function (global) {

    'use strict';

    const logger = WorkflowUtil.newLogger("WorkflowApp/View");
    
    // language=JSRegexp
    const doubleByteReg = new RegExp("[\\u4E00-\\u9FFF]+");

    const FONT_FAMILY = "Helvetica, Arial, sans-serif";

    // icon 缓存
    const ICON_MAP = {};
    const EVENT_MAP = {};
    
    const DEFALUT_CONFIG = {
        icon_size: 40,//头像直径
        icon_margin_tb: 5,//头像和上下文字的距离
        icon_margin_lr: 40,//头像和整个节点边框的距离
        icon_margin_line_lr: 10,//头像和线之间的距离
        blank_size: 20,//空节点大小（直径）
        line_height: 1.5,//行高
        font_size: 16//文字大小
    };


    /**
     *
     * {
     *   container : "#main",
     *   model : model
     * }
     * 
     */
    function View(setting) {

        const DEFAULT_SETTING = {

            container : "",
            model : null
        };

        // 页面配置信息
        this.setting = WorkflowUtil.merge(setting, DEFAULT_SETTING);
        
        this.model = this.setting.model;

        // 页面布局信息
        this.layoutInfo = {
                
            //节点宽度
            nodeWidth : 0,
            
          //节点高度
            nodeHeight : 0,
            
          //头部文字相对偏移量
            topOneLineTextOffset : [0, 0],
            topTwoLineTextOffset : [0, 0],
            
          //头像相对偏移量
            iconOffset : [0, 0],
    
         //左边连线点偏移量
            leftLineOffset : [0, 0],
            
          //右边连线点偏移量
            rightLineOffset : [0, 0],
            
          //空节点圆圈的偏移量
            blankOffset : [0, 0],
    
        //底部文字偏移量
            bottonTextOffset : [0, 0],
            
            // 当前缩放比例
            zoom : 1,
            minZoom : 1,
            maxZoom : 5,
            
            // 画布大小
            svgHeight : 0,
            svgWidth : 0,
            
            // 可视区域大小
            viewHeight : 0,
            viewWidth : 0,
            
            // 缩放展示区域大小
            viewBoxX : 0,
            viewBoxY : 0,
            viewBoxWidht : 0,
            viewBoxHeight : 0
        };

        //dom相关元素缓存
        this.container = this.setting.container;
        this.svg = null;
        this.defs = null;
        this.menu = null;
        this.toobarBtnSize = 0;
        
        // 1 倍配置设置流程图
        this.nodeConfig = WorkflowUtil.merge({}, DEFALUT_CONFIG);
        this._scaleConfig(1);
    }
    
    View.prototype.setModel = function(model){
        this.model = model;
    };


    /**
     * 根据缩放大小重新计算数据
     */
    View.prototype._scaleConfig = function (scale) {
        
        for (let key in this.nodeConfig) {
            if(this.nodeConfig.hasOwnProperty(key)){
                this.nodeConfig[key] *= scale;
            }
        }

        let config = this.nodeConfig;

        //Node Width
        this.layoutInfo.nodeWidth = config.icon_size + 2 * config.icon_margin_lr;

        //Top name height
        this.nodeNameHeight = /*1 * */config.font_size * config.line_height + config.font_size;

        //Node Height
        this.layoutInfo.nodeHeight = config.icon_size
            + 2 * config.icon_margin_tb
            + this.nodeNameHeight
            + /*1 * */config.font_size * config.line_height;

        let textX = this.layoutInfo.nodeWidth / 2;

        //Node name text x and y location for one line
        this.layoutInfo.topOneLineTextOffset = [textX, /*1 * */config.font_size * config.line_height - 5];
        //Node name text x and y location for two line
        this.layoutInfo.topTwoLineTextOffset = [0, 0];


        //Node icon x and y location
        this.layoutInfo.iconOffset = [config.icon_margin_lr,
            this.nodeNameHeight + config.icon_margin_tb];

        //Node left line end point location
        this.layoutInfo.leftLineOffset = [config.icon_margin_lr - config.icon_margin_line_lr,
            this.layoutInfo.iconOffset[1] + (config.icon_size / 2)];

        //Node right line start point location
        this.layoutInfo.rightLineOffset = [config.icon_margin_lr + config.icon_size
        + config.icon_margin_line_lr,
            this.layoutInfo.leftLineOffset[1]];

        //Blank Node x and y loction
        this.layoutInfo.blankOffset = [(config.icon_size - config.blank_size) / 2 + this.layoutInfo.iconOffset[0],
            (config.icon_size - config.blank_size) / 2 + this.layoutInfo.iconOffset[1]];

        //Node policy x and y location
        this.layoutInfo.bottonTextOffset = [textX, this.layoutInfo.iconOffset[1] + config.icon_size
        + config.icon_margin_tb];
    };
    
    
    /**
     * 获取图标
     */
    View.prototype._getDefIcon = function(iconName, useImg, url){

        let defIcon = ICON_MAP[iconName];
        if(!defIcon){

            // FIXME 人员头像

            let def = {useImg : !!useImg};
            if(!useImg){
                def = {
                    width : this.nodeConfig.icon_size,
                    height : this.nodeConfig.icon_size,
                    imageData : url || "icon/user-14.gif",
                    useImg : !!useImg
                    //useImg : true
                }
            }

            const img = SVGUtil.getDefIcon(iconName, def);

            //const randId = ViewUtil.randId(img);

            const iconId = "icon_" + iconName;
            SVGUtil.setAttr(img, "id", iconId);
            this.defs.appendChild(img);
            
            ICON_MAP[iconName] = iconId;
            defIcon = iconId;
        }
        return defIcon;
    };
    

    /**
     * 画图
     */
    View.prototype.draw = function () {

        const process = this.model.getProcess();

        let maxX = process.getMaxX();
        let maxY = process.getMaxY();

        let width = (maxX + 3) * this.layoutInfo.nodeWidth;
        let height = (maxY + 3) * this.layoutInfo.nodeHeight;

        //容器
        let $container = ViewUtil.query(this.container);
        this.layoutInfo.viewWidth = $container.clientWidth;
        this.layoutInfo.viewHeight = $container.clientHeight;

        this.layoutInfo.svgWidth = Math.max(width, this.layoutInfo.viewWidth);
        this.layoutInfo.svgHeight = Math.max(height, this.layoutInfo.viewHeight);

        if (this.svg == null) {
            this.svg = SVGUtil.create("svg");
            
            this.defs = SVGUtil.create("defs");
            this.svg.appendChild(this.defs);
        }

        logger.debug("画布大小: width=" + this.layoutInfo.svgWidth + ", height=" + this.layoutInfo.svgHeight);
        logger.debug("容器大小: width=" + this.layoutInfo.viewWidth + ", height=" + this.layoutInfo.viewHeight);

        SVGUtil.setAttr(this.svg, "width", this.layoutInfo.viewWidth);
        SVGUtil.setAttr(this.svg, "height", this.layoutInfo.viewHeight);

        let drawed = {};
        
        
        let startTime = new Date().getTime();
        this._drawNode(process.getStartNode(), drawed);


        //缩放计算
        this.layoutInfo.viewBoxX = 0;
        this.layoutInfo.viewBoxY = 0;
        this.layoutInfo.viewBoxWidht = this.layoutInfo.svgWidth;
        this.layoutInfo.viewBoxHeight = this.layoutInfo.svgHeight;
        this.layoutInfo.minZoom = Math.min(ViewUtil.effectiveValue(this.layoutInfo.viewWidth / this.layoutInfo.viewBoxWidht, 2),
                                           ViewUtil.effectiveValue(this.layoutInfo.viewHeight / this.layoutInfo.viewBoxHeight, 2));

        this._scale();

        SVGUtil.setAttr(this.svg, "preserveAspectRatio", "xMidYMid meet");

        //添加到dom上面
        $container.style.overflow = "hidden";
        $container.style.position = "relative";

        this._createToolbar($container);
        //添加事件
        this._listener($container);

        $container.appendChild(this.svg);


        let endTime = new Date().getTime();
        logger.debug("画图耗时: " + (endTime - startTime) + " ms")
    };

    /**
     *  添加事件
     */
    View.prototype._listener = function ($container) {

        let _this = this;
        //滚轮事件
        ViewUtil.addEvent($container, "mousewheel", function (ev) {
            if (ev.delta < 0) {
                //缩小
                _this._changeViewBox(-0.2);
            } else if (ev.delta > 0) {
                //放大
                _this._changeViewBox(0.2);
            }
        });


        //拖拽事件
        //$container.style.cursor = "move";
        ViewUtil.addEvent($container, "mousedown", function (ev) {

            let oevent = ev || event;

            if (oevent.stopPropagation)
                oevent.stopPropagation();
            else
                oevent.cancelBubble = true;


            let x = oevent.clientX;
            let y = oevent.clientY;

            let moveEvent, endEvent;
            
            ViewUtil.addEvent(document, "mousemove", moveEvent = function (ev) {

                let oevent = ev || event;
                if (oevent.preventDefault) {
                    oevent.preventDefault()
                } else {
                    oevent.returnValue = false
                }


                let newX = oevent.clientX;
                let newY = oevent.clientY;

                let distanceX = newX - x;
                let distanceY = newY - y;
                x = newX;
                y = newY;

                //根据zoom进行换算
                let weight = 1 / _this.layoutInfo.zoom;
                distanceX = weight * distanceX;
                distanceY = weight * distanceY;

                let newViewBoxX = _this.layoutInfo.viewBoxX - distanceX;
                let newViewBoxY = _this.layoutInfo.viewBoxY - distanceY;

                newViewBoxX = Math.min(newViewBoxX, _this.layoutInfo.svgWidth - _this.layoutInfo.viewBoxWidht);
                newViewBoxX = Math.max(newViewBoxX, 0);
                _this.layoutInfo.viewBoxX = newViewBoxX;

                newViewBoxY = Math.min(newViewBoxY, _this.layoutInfo.svgHeight - _this.layoutInfo.viewBoxHeight);
                newViewBoxY = Math.max(newViewBoxY, 0);
                _this.layoutInfo.viewBoxY = newViewBoxY;
                _this._scale(true);
            });
            ViewUtil.addEvent(document, "mouseup", endEvent = function () {
                ViewUtil.removeEvent(document, "mousemove", moveEvent);
                ViewUtil.removeEvent(document, "mouseup", endEvent);
                moveEvent = null;
                endEvent = null;
            });
        });
    };

    /**
     * 创建toolbar
     */
    View.prototype._createToolbar = function ($container) {

        let _this = this;

        this._createToolbarBtn($container, "放大", function (e) {
            e.stopPropagation();
            _this._changeViewBox(0.2);
        });

        this._createToolbarBtn($container, "缩小", function (e) {
            e.stopPropagation();
            _this._changeViewBox(-0.2);
        });

        this._createToolbarBtn($container, "最小", function (e) {
            e.stopPropagation();
            _this._changeViewBox(_this.layoutInfo.minZoom, true);
        });

        this._createToolbarBtn($container, "原始", function (e) {
            e.stopPropagation();
            _this._changeViewBox(1, true);
        });
    };

    View.prototype._createToolbarBtn = function ($container, name, fn) {

        let btn = document.createElement("div");
        btn.style.cssText = "position:absolute;width:60px;height:30px;" +
            "line-height:30px;text-align:center;background-color:green;top:5px;" +
            "left:" + (this.toobarBtnSize * 65 + 5) + "px;cursor:default";
        btn.innerText = name;
        $container.appendChild(btn);

        ViewUtil.addEvent(btn, "click", fn);

        this.toobarBtnSize++;
    };

    /**
     * 更新ViewBox参数用于缩放
     * @param isAbs 是否是绝对缩放， true - step 表示目标缩放比率， false - 表示相对于现在比例进行相对缩放
     * @param step
     */
    View.prototype._changeViewBox = function (step, isAbs) {

        let newViewBoxWidth, newViewBoxHeight;

        if (isAbs){


            let newZoom = Math.abs(step);

            if(this.layoutInfo.zoom === step){
                return;
            }

            if(newZoom > this.layoutInfo.maxZoom){
                newZoom = this.layoutInfo.maxZoom;
            }
            if(newZoom < this.layoutInfo.minZoom){
                newZoom = this.layoutInfo.minZoom;
            }

            newViewBoxWidth = Math.ceil(this.layoutInfo.viewWidth / newZoom);
            newViewBoxHeight = Math.ceil(this.layoutInfo.viewHeight / newZoom);

        }else{


            if (step > 0) {
                //放大
                if (this.layoutInfo.zoom === this.layoutInfo.maxZoom) {
                    return;
                }
            } else {
                //缩小
                if (this.layoutInfo.zoom === this.layoutInfo.minZoom) {
                    return;
                }
            }

            let absStep = Math.abs(step), operator = step < 0 ? 1 : -1;

            //缩小/放大相对值
            newViewBoxWidth = Math.ceil(this.layoutInfo.viewBoxWidht + this.layoutInfo.viewBoxWidht * absStep * operator);
            newViewBoxHeight = Math.ceil(this.layoutInfo.viewBoxHeight + this.layoutInfo.viewBoxHeight * absStep * operator);
        }



        if(newViewBoxWidth <= 0 || newViewBoxHeight <= 0){
            newViewBoxWidth = this.layoutInfo.viewWidth;
            newViewBoxHeight = this.layoutInfo.viewHeight;
        }

        if(newViewBoxWidth > this.layoutInfo.svgWidth || newViewBoxHeight > this.layoutInfo.svgHeight){
            newViewBoxWidth = this.layoutInfo.svgWidth;
            newViewBoxHeight = this.layoutInfo.svgHeight;
        }

        //从中心缩放
        let dx = (this.layoutInfo.viewBoxWidht - newViewBoxWidth) / 2;
        let dy = (this.layoutInfo.viewBoxHeight - newViewBoxHeight) / 2;

        let newViewBoxX = this.layoutInfo.viewBoxX + dx;
        let newViewBoxY = this.layoutInfo.viewBoxY + dy;

        newViewBoxX = Math.max(newViewBoxX, 0);
        newViewBoxY = Math.max(newViewBoxY, 0);

        this.layoutInfo.viewBoxWidht = newViewBoxWidth;
        this.layoutInfo.viewBoxHeight = newViewBoxHeight;
        this.layoutInfo.viewBoxX = newViewBoxX;
        this.layoutInfo.viewBoxY = newViewBoxY;

        //执行缩放
        this._scale();
    };

    /**
     * 放大或缩小流程图
     */
    View.prototype._scale = function (move) {

        let viewBoxValue = this.layoutInfo.viewBoxX + "," + this.layoutInfo.viewBoxY;
        viewBoxValue += "," + this.layoutInfo.viewBoxWidht + "," + this.layoutInfo.viewBoxHeight;

        //logger.debug("viewBoxValue=" + viewBoxValue);

        SVGUtil.setAttr(this.svg, "viewBox", viewBoxValue);

        //非移动情况下
        if (move !== true) {

            this.layoutInfo.zoom = Math.min(ViewUtil.effectiveValue(this.layoutInfo.viewWidth / this.layoutInfo.viewBoxWidht, 2),
                                    ViewUtil.effectiveValue(this.layoutInfo.viewHeight / this.layoutInfo.viewBoxHeight, 2));

            this.layoutInfo.zoom = Math.max(this.layoutInfo.zoom, this.layoutInfo.minZoom);
            this.layoutInfo.zoom = Math.min(this.layoutInfo.zoom, this.layoutInfo.maxZoom);

            logger.debug("缩放情况:minZoom=" + this.minZoom + ", maxZoom=" + this.layoutInfo.maxZoom + ", zoom=" + this.layoutInfo.zoom);
        }
    };

    /**
     * 解析节点名字， 一行和两行显示
     */
    View.prototype._resolveName = function (name) {

        let ret = [];
        let nameLength = name.length;
        let isChiness = false;
        for (let i = 0; i < nameLength; i++) {
            if (doubleByteReg.test(name.charAt(i))) {
                isChiness = true;
                break;
            }
        }

        if (isChiness) {
            if (name.length >= 9 && name.length <= 16) {
                ret.push(name.slice(0, 8));
                ret.push(name.slice(8, 16));

            } else if (name.length > 16) {
                ret.push(name.slice(0, 8));
                ret.push(name.slice(8, 16) + "...");
            } else {
                ret.push(name);
            }
        } else {
            // 英文名字的规则： 同一个单词不能换行
            if (name.length > 13) {

                let nameWord = name.split(" ");
                let lineCount = 1;
                let currentStr = "";
                let displayStr = "";
                for (let i = 0; i < nameWord.length; i++) {

                    let word = nameWord[i];
                    // 第一行
                    if (lineCount === 1) {

                        // 1 是空格
                        if (currentStr.length + 1 + word.length > 13) {

                            if (currentStr === "") {
                                word = name.slice(0, 11) + "...";
                                currentStr = "";
                                displayStr += word;
                            } else {
                                displayStr += currentStr;
                                currentStr = word;
                            }
                            //第一行
                            ret.push(displayStr);
                            displayStr = "";

                            // 换行
                            lineCount++;
                        } else {
                            currentStr += " " + word;
                        }
                    } else {
                        if (currentStr !== "") {
                            currentStr += " ";
                        }
                        currentStr += word;
                    }
                }

                if (lineCount > 1 && currentStr !== "") {
                    if (currentStr.length > 13) {
                        currentStr = currentStr.slice(0, 11) + "...";
                    }

                    //第二行
                    ret.push(currentStr);
                }
            } else {
                ret.push(name);
            }
        }

        return ret;
    };

    /**
     * 绘制空节点
     * @param nodeGroup
     * @private
     */
    View.prototype._drawBlankNode = function(nodeGroup){

        let blankCircle = SVGUtil.create("circle");
        let blankRadius = this.nodeConfig.blank_size / 2;
        SVGUtil.setAttr(blankCircle, "r", blankRadius);
        SVGUtil.setAttr(blankCircle, "cx", this.layoutInfo.blankOffset[0] + blankRadius);
        SVGUtil.setAttr(blankCircle, "cy", this.layoutInfo.blankOffset[1] + blankRadius);

        SVGUtil.setAttr(blankCircle, "fill", "none");
        SVGUtil.setAttr(blankCircle, "stroke-linejoin", "round");
        SVGUtil.setAttr(blankCircle, "stroke-linecap", "round");
        SVGUtil.setAttr(blankCircle, "stroke", "#0000ff");
        SVGUtil.setAttr(blankCircle, "stroke-width", "1");

        nodeGroup.appendChild(blankCircle);
    };


    /**
     * 绘制节点名称
     * @param nodeGroup
     * @param node
     * @private
     */
    View.prototype._drawNodeName = function(nodeGroup, node){

        if(!node.isEnd()){

            let name = node.getName();
            if (name) {

                let nameArray = this._resolveName(name);

                let nameText = SVGUtil.create("text");
                SVGUtil.setAttr(nameText, "font-family", FONT_FAMILY);
                SVGUtil.setAttr(nameText, "font-size", this.nodeConfig.font_size + "px");

                if (nameArray.length > 1) {

                    SVGUtil.setAttr(nameText, "x", this.layoutInfo.topTwoLineTextOffset[0]);
                    SVGUtil.setAttr(nameText, "y", this.layoutInfo.topTwoLineTextOffset[1]);

                    //两行
                    let nameLine1 = SVGUtil.create("tspan");
                    nameLine1.appendChild(SVGUtil.newText(nameArray[0]));
                    SVGUtil.setAttr(nameLine1, "dy", this.nodeConfig.font_size);

                    let nameLine2 = SVGUtil.create("tspan");
                    nameLine2.appendChild(SVGUtil.newText(nameArray[1]));
                    SVGUtil.setAttr(nameLine2, "x", this.layoutInfo.topTwoLineTextOffset[0]);
                    SVGUtil.setAttr(nameLine2, "dy", this.nodeConfig.font_size
                        * this.nodeConfig.line_height);

                    nameText.appendChild(nameLine1);
                    nameText.appendChild(nameLine2);

                } else {

                    SVGUtil.setAttr(nameText, "x", this.layoutInfo.topOneLineTextOffset[0]);
                    SVGUtil.setAttr(nameText, "y", this.layoutInfo.topOneLineTextOffset[1]
                        + this.nodeConfig.font_size);

                    //文字居中
                    //nameText.style.cssText = "dominant-baseline: middle; text-anchor: middle;";
                    nameText.style.cssText = "text-anchor: middle;";
                    nameText.appendChild(SVGUtil.newText(nameArray[0]));
                }

                //设置title
                let titleNode = SVGUtil.create("title");
                titleNode.appendChild(SVGUtil.newText(name));
                nameText.appendChild(titleNode);

                nodeGroup.appendChild(nameText);
            }
        }
    };


    /**
     * 绘制节点权限名称
     * @param nodeGroup
     * @param node
     * @private
     */
    View.prototype._drawPolicyName = function(nodeGroup, node){

        if(!node.isStart() && !node.isEnd()){

            //节点权限
            let policyName = node.getPolicyName();
            if (policyName) {
                policyName = "[" + policyName + "]";
            }
            if (policyName) {

                //节点权限
                let policyText = SVGUtil.create("text");
                policyText.appendChild(SVGUtil.newText(policyName));
                SVGUtil.setAttr(policyText, "font-family", FONT_FAMILY);
                SVGUtil.setAttr(policyText, "font-size", this.nodeConfig.font_size + "px");
                SVGUtil.setAttr(policyText, "x", this.layoutInfo.bottonTextOffset[0]);
                SVGUtil.setAttr(policyText, "y", this.layoutInfo.bottonTextOffset[1] + this.nodeConfig.font_size);
                policyText.style.cssText = "text-anchor:middle;";

                nodeGroup.appendChild(policyText);
            }
        }
    };


    /**
     * 绘制头像
     * @param nodeGroup
     * @param node
     * @private
     */
    View.prototype._drawNodeIcon = function(nodeGroup, node){

        const actor = node.getActor();
        //const policy = node.getPolicy();

        let nodeIconCode = "nodeicon", nodeIconURL;
        if(node.isEnd()){
            nodeIconCode += "_" + node.getId();
        }else{
            let partyType = actor.getPartyType();
            nodeIconCode += "_" + partyType;
            if("user" === partyType){
                nodeIconCode += "_" + actor.getPartyId();
                // FIXME 人员头像 nodeIconURL
            }
        }
        let nodeIconId = this._getDefIcon(nodeIconCode, nodeIconURL);
        let circleRadius = this.nodeConfig.icon_size / 2;

        // 使用 circle 绘制头像
        let headCircle = SVGUtil.create("circle");
        SVGUtil.setAttr(headCircle, "r", circleRadius);
        SVGUtil.setAttr(headCircle, "cx", this.layoutInfo.iconOffset[0] + circleRadius);
        SVGUtil.setAttr(headCircle, "cy", this.layoutInfo.iconOffset[1] + circleRadius);
        //SVGUtil.setAttr(headCircle, "fill", "#44c0ff");
        SVGUtil.setAttr(headCircle, "fill", "url(#" + nodeIconId + ")");

        /*// 使用image绘制头像
        let headCircle = SVGUtil.create("use");
        SVGUtil.setAttr(headCircle, "xlink:href", "#" + nodeIconId);
        SVGUtil.setAttr(headCircle, "x", this.layoutInfo.iconOffset[0]);
        SVGUtil.setAttr(headCircle, "y", this.layoutInfo.iconOffset[1]);
        */

        // FIXME 图标
        // FIXME 超级节点
        nodeGroup.appendChild(headCircle);
        /*ViewUtil.addEvent(use, "mouseover", function(){
            alert(SVGUtil.getAttr(this, "conditionTitle"));
        });*/
    };


    /**
     * 获取节点状态
     * @private
     */
    View.prototype._getNodeState = function(node){

        const policy = node.getPolicy();

        let state, nodeState, isReadState = false, workitems = [];
        state = nodeState = node.getState();

        const caseItemLog = this.model.getCaseItemLog();
        if (caseItemLog) {
            workitems = caseItemLog.getWorkItems(node.getId());
            if (workitems.length > 0) {
                isReadState = workitems[0].isRead();
            }
        }

        // 节点状态解析
        for (let i = 0; i < workitems.length; i++) {

            const workitem = workitems[i];
            const itemAction = workitem.getItemAction();
            const itemIsRead = workitem.isRead();

            if (state === WorkflowConstant.nodeState.STATE_READY.STATE_READY
                || state === WorkflowConstant.nodeState.STATE_INFORM) {

                if (itemAction === WorkflowConstant.WorkitemAction.ACTION_FINISHED
                    || WorkflowConstant.WorkitemAction.ACTION_ZCDB) {

                    state = WorkflowConstant.nodeState.STATE_ZCDB;
                    isReadState = itemIsRead;

                } else if (itemAction === WorkflowConstant.WorkitemAction.ACTION_STOP) {

                    //被终止
                    state = WorkflowConstant.nodeState.STATE_STOP_PASSIVITY;

                } else if (itemAction === WorkflowConstant.WorkitemAction.ACTION_STOP_EXECUTOR) {

                    //终止
                    state = WorkflowConstant.nodeState.STATE_STOP;

                }
            } else if (state === WorkflowConstant.nodeState.STATE_FINISHED) {

                if (itemAction === WorkflowConstant.WorkitemAction.ACTION_AUTO_SKIP_OVER) {

                    //节点自动跳过状态
                    state = WorkflowConstant.nodeState.STATE_AUTO_SKIP;

                }

            } else if (state === WorkflowConstant.nodeState.STATE_STOP) {

                if (itemAction === WorkflowConstant.WorkitemAction.ACTION_STOP) {
                    //被终止
                    state = WorkflowConstant.nodeState.STATE_STOP_PASSIVITY;
                }

            } else if (state === WorkflowConstant.nodeState.STATE_STOP_PASSIVITY) {

                if (itemAction === WorkflowConstant.WorkitemAction.ACTION_STOP_EXECUTOR) {
                    //终止, FIXME 这里感觉是有问题的， 和上面的逻辑不一致, 现在是flash的逻辑
                    state = WorkflowConstant.nodeState.STATE_STOP_24;
                }

            } else {
                // 不再循环了
                break;
            }
        }


        if(node.isBlank()){

            if(state === WorkflowConstant.nodeState.STATE_READY){
                state = WorkflowConstant.nodeState.STATE_FINISHED;
            }
        } else if(state === WorkflowConstant.nodeState.STATE_FINISHED
            && policy.getNa() === global.BPMSeeyonPolicy.na_2_NOT_MATCH_SKIP){
            if(workitems.length === 0){
                // 自动跳过
                state = WorkflowConstant.nodeState.STATE_AUTO_SKIP;
            }
        }

        return {"state" : state, "nodeState" : nodeState, "isReadState" : isReadState}
    };


    /**
     * 画节点
     * @param node
     * @param drawed
     * @param link
     */
    View.prototype._drawNode = function (node, drawed, link) {

        if (drawed[node.getId()]) {
            return {"node" : node, "fromLink" : link};
        }

        drawed[node.getId()] = node.getId();
        let drawThis = false;

        //合并路由节点
        if (!node.isSkip()) {

            drawThis = true;

            let x = (node.getX() + 1) * this.layoutInfo.nodeWidth;
            let y = (node.getY() + 1) * this.layoutInfo.nodeHeight;

            // logger.debug("绘制节点: " + node.getName() + "(" + node.getId() + ")"
            //                 + " - x=" + x + ", y=" + y);

            if (!node.isJoin() && !node.isSplit()) {

                let nodeGroup = SVGUtil.create("g");
                SVGUtil.setAttr(nodeGroup, "transform", "matrix(1,0,0,1," + x + "," + y + ")");
                SVGUtil.setAttr(nodeGroup, "id", "Node_" + node.getId());

                if (node.isBlank()) {

                    // 画空节点
                    this._drawBlankNode(nodeGroup);
                } else {

                    // 节点名称
                    this._drawNodeName(nodeGroup, node);

                    // 节点权限名称
                    this._drawPolicyName(nodeGroup, node);


                    // 绘制头像
                    this._drawNodeIcon(nodeGroup, node);


                    // const actor = node.getActor();
                    // const policy = node.getPolicy();

                    if (!node.isStart()) {

                        const {state, nodeState, isReadState} = this._getNodeState(node);
                    }

                    // FIXME 节点校验没有通过时显示
                    // FIXME 竞争图标
                    // FIXME 流程事件图标
                    // FIXME 节点状态
                    // FIXME 设置子流程
                    // FIXME 设置催办
                    // FIXME 当前节点颜色设置
                    // FIXME copy 和 parse 显示
                    // FIXME 状态异常显示
                    // FIXME 流程仿真多个节点标记颜色
                    // FIXME 指定回退图标
                }

                this.svg.appendChild(nodeGroup);

            } else {
                if (node.isSplit()) {
                    //split节点
                } else {
                    //join节点
                }
            }
        }

        const downLinks = node.getDownLinks();
        if (downLinks && downLinks.length > 0) {

            for (let i = 0; i < downLinks.length; i++) {

                const downLink = downLinks[i];
                let subNode = downLink.getToNode();
                if (subNode.isHidden()) {
                    continue;
                }

                const downNodeInfo = this._drawNode(subNode, drawed, downLink);
                let lineNode = downNodeInfo["node"];
                let fromLink = downNodeInfo["fromLink"];

                if (drawThis && !lineNode.isSkip()) {
                    //连线
                    this._drawLine(node, downLink, lineNode, fromLink);
                }

                if (node.getNextLineSize() === 1 && !drawThis) {
                    return {"node" : lineNode, "fromLink" : fromLink};
                }
            }
        }

        return {"node" : node, "fromLink" : link};
    };

    /**
     * 画线
     * @param from
     * @param downLink
     * @param to
     * @param fromLine
     */
    View.prototype._drawLine = function (from, downLink, to, fromLine) {

        //logger.debug("绘制线: " + fromNode.getName() + "(" + fromNode.getId() + ")"
        //                 + " -> " + toNode.getName() + "(" + toNode.getId() + ")");

        let x1 = (from.getX() + 1) * this.layoutInfo.nodeWidth;
        let y1 = (from.getY() + 1) * this.layoutInfo.nodeHeight;

        let x2 = (to.getX() + 1) * this.layoutInfo.nodeWidth;
        let y2 = (to.getY() + 1) * this.layoutInfo.nodeHeight;

        
        let fromLocation = this._getLineLocation(from, x1, y1, this.layoutInfo.rightLineOffset[0]);
        let toLocation = this._getLineLocation(to, x2, y2, this.layoutInfo.leftLineOffset[0]);

        let points = [];
        points.push(fromLocation);

        if (y1 === y2) {
            //两点在一条直线上
        } else {
            //需要中间点
            let third = [];

            if (from.isSplit()) {
                third.push(fromLocation[0]);
                third.push(toLocation[1]);
            } else if (to.isJoin()) {
                third.push(toLocation[0]);
                third.push(fromLocation[1]);
            } else {
                //没有这种情况
            }
            points.push(third);
        }
        points.push(toLocation);


        let strokeDasharray = "";
        if (to.isVirtual() || from.isVirtual()) {
            strokeDasharray = "stroke-dasharray:5 5;";
        }

        let cssTextVal = "fill:none;stroke:blue;stroke-width:1px;shape-rendering: crispEdges;";
        cssTextVal += strokeDasharray;

        //一条线画完
        // let polyline = SVGUtil.create("polyline");
        // let pointsStr = "";
        // for(let i = 0, pointsLength = points.length; i < pointsLength; i++){
        //   let p = points[i];
        //   pointsStr += p[0] + "," + p[1] + " ";
        // }
        // SVGUtil.setAttr(polyline, "points", pointsStr);
        // polyline.style.cssText = cssTextVal;
        // this.svg.appendChild(polyline);

        let pX1, pY1, pX2, pY2, pX3, pY3;
        pX1 = points[0][0];
        pY1 = points[0][1];
        pX2 = points[1][0];
        pY2 = points[1][1];

        let drawFirstLine = true;
        if(pY1 !== pY2 && from.isSplit()){
            if(downLink.getId() !== from.getFirstLineId()
                    && downLink.getId() !== from.getLastLineId()){
                drawFirstLine = false;
            }
        }

        let conditionLine = null;

        if(drawFirstLine){
            
            let line1 = SVGUtil.create("line");
            line1.style.cssText = cssTextVal;
            SVGUtil.setAttr(line1, "x1", pX1);
            SVGUtil.setAttr(line1, "y1", pY1);
            SVGUtil.setAttr(line1, "x2", pX2);
            SVGUtil.setAttr(line1, "y2", pY2);
            this.svg.appendChild(line1);
            
            // 事件线
            if(pY1 === pY2){
                conditionLine = line1;
            }
        }

        let conditionLineStartX = points[0][0];
        let conditionLineEndX = points[1][0];

        let conditionLineY = points[1][1];

        if (points.length > 2) {
            
            pX3 = points[2][0];
            pY3 = points[2][1];

            let drawSecondLine = true;
            if(pY2 !== pY3 && to.isJoin()){
                
                 if(fromLine.getId() !== to.getFirstLineId()
                         && fromLine.getId() !== to.getLastLineId()){
                     drawSecondLine = false;
                 }
            }

            if(drawSecondLine){

                let line2 = SVGUtil.create("line");
                line2.style.cssText = cssTextVal;
                SVGUtil.setAttr(line2, "x1", pX3);
                SVGUtil.setAttr(line2, "y1", pY3);
                SVGUtil.setAttr(line2, "x2", pX2);
                SVGUtil.setAttr(line2, "y2", pY2);
                this.svg.appendChild(line2);

                if(pY2 === pY3){
                    conditionLine = line2;
                }

                conditionLineStartX = pX2;
                conditionLineEndX = pX3;
                conditionLineY = pY3;
            }
        }
        
     // 展示分支条件
        const lineId = fromLine.getId() || "";
        const conditionType = fromLine.getConditionType() || "";
        const isForce = fromLine.getIsForce() || "";
        const conditionBase = fromLine.getConditionBase() || "";
        const conditionTitle = fromLine.getConditionTitle() || "";

        //设置线的ID
        SVGUtil.setAttr(conditionLine, "id", "Line_" + lineId);

        let branchIcon = "";
        if(conditionType === WorkflowConstant.ConditionType.autoCondition1
                || conditionType === WorkflowConstant.ConditionType.autoCondition4){// 自动分支
            if(isForce === "1"){
                // 强制分支
                branchIcon = "branch_auto_force";
            } else{
                // 非强制分支
                branchIcon = "branch_auto_manual";
            }
        } else if(conditionType === WorkflowConstant.ConditionType.handCondition){//手动分支
            branchIcon = "branch_manual";
        } else{// 普通线
            
        }


        // FIXME 分支校验没有通过的时候需要显示
        // FIXME 分支条件鼠标移动上去交互



        if(branchIcon){

            branchIcon = "branch_auto_force";

            // 在conditionLine 这条线上划图标
            //this.svg
            const defIconId = this._getDefIcon(branchIcon, true);
            const use = SVGUtil.create("use");
            SVGUtil.setAttr(use, "xlink:href", "#" + defIconId);
            ViewUtil.addEvent(use, "mouseover", function(){
                //alert(SVGUtil.getAttr(this, "conditionTitle"));
            });

            ViewUtil.addEvent(use, "mouseleave", function(){

            });


            const conditionX = (conditionLineStartX + conditionLineEndX) / 2 - 12;
            const conditionY = conditionLineY - 24;

            SVGUtil.setAttr(use, "conditionTitle", conditionTitle);

            SVGUtil.setAttr(use, "x", conditionX);
            SVGUtil.setAttr(use, "y", conditionY);

            //增加
            this.svg.appendChild(use);
        }

        // 添加事件
        if(!to.isJoin()){

            // 加粗
            conditionLine.style.strokeWidth = "5px";
            const toLineId = fromLine.getId();

            const clickName = toLineId + "_click";
            //const mouseoverName = toLineId + "_mouseover";
            //const mouseoutName = toLineId + "_mouseout";

            EVENT_MAP[clickName] = function(e){

                const viewObject = this.viewObject;
                // 创建菜单
                viewObject._createMenu(e, SVGUtil.getAttr(this, "x2"), SVGUtil.getAttr(this, "y2"));
            };
           /* EVENT_MAP[mouseoverName] = function(e){
                this.style.strokeWidth = "10px";
            };
            EVENT_MAP[mouseoutName] = function(e){
                this.style.strokeWidth = "5px";
            };*/

            // 将viewObject 绑定到线上
            conditionLine.viewObject = this;
            ViewUtil.addEvent(conditionLine, "click", EVENT_MAP[clickName]);
            //ViewUtil.addEvent(conditionLine, "mouseover", EVENT_MAP[mouseoverName]);
            //ViewUtil.addEvent(conditionLine, "mouseout", EVENT_MAP[mouseoutName]);

            // FIXME 注意注销元素的时候， 需要解除绑定， 移除 viewObject 对象
        }
    };


    /**
     * 创建菜单
     * @private
     */
    View.prototype._createMenu = function(e, x, y){

        const menu = SVGUtil.create("g");
        SVGUtil.setAttr(menu, "transform", "matrix(1,0,0,1," + x + "," + y + ")");
        //SVGUtil.setAttr(menu, "fill", "#fff");

        const items = [];
        items.push({
            name : "菜单1"
        });
        items.push({
            name : "菜单2"
        });
        items.push({
            name : "菜单3"
        });

        /*const background = SVGUtil.create("rect");
        SVGUtil.setAttr(background, "fill", "#fff");
        SVGUtil.setAttr(background, "width", "100%");
        SVGUtil.setAttr(background, "height", "49");
        menu.appendChild(background);*/


        for(let i = 0; i < items.length; i++){

            const m = items[i];

            const item = SVGUtil.create("text");
            SVGUtil.setAttr(item, "font-family", FONT_FAMILY);
            SVGUtil.setAttr(item, "font-size", this.nodeConfig.font_size + "px");
            SVGUtil.setAttr(item, "x", 0);
            SVGUtil.setAttr(item, "y", i * this.nodeConfig.font_size + 5);
            item.appendChild(SVGUtil.newText(m.name));

            menu.appendChild(item);
        }

        this.svg.appendChild(menu);

        this.menu = menu;
    };

    /**
     *
     * 获取节点连线的位置
     *
     * @param from
     * @param x1
     * @param y1
     * @param offset
     * @returns {Array}
     * @private
     */
    View.prototype._getLineLocation = function (from, x1, y1, offset) {

        let ret = [];
        //let config = this.nodeConfig;

        if (from.isJoin() || from.isSplit()) {
            ret.push(x1 + (this.layoutInfo.nodeWidth / 2));
        } else {
            ret.push(x1 + offset);
        }

        ret.push(y1 + this.layoutInfo.leftLineOffset[1]);

        return ret;
    };

    global.View = View;

})(WorkflowApp);
